package org.summerframework.component.security.role.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.summerframework.component.mybatisplus.AbstractBasePlusService;
import org.summerframework.component.security.RoleResultCode;
import org.summerframework.component.security.events.RoleChangeEvent;
import org.summerframework.component.security.permissions.service.UserPermissionsRoleRelService;
import org.summerframework.component.security.permissions.service.dto.UserPermissionsRoleRelDTO;
import org.summerframework.component.security.role.model.dao.UserRoleDAO;
import org.summerframework.component.security.role.model.domain.UserRoleDO;
import org.summerframework.component.security.role.service.UserRoleRelService;
import org.summerframework.component.security.role.service.UserRoleService;
import org.summerframework.component.security.role.service.dto.UserRoleDTO;
import org.summerframework.component.security.role.service.dto.UserRoleQueryDTO;
import org.summerframework.component.security.role.service.dto.UserRoleRelDTO;
import org.summerframework.component.security.role.service.dto.UserRoleRelQueryDTO;
import org.summerframework.core.base.result.DefaultResultCode;
import org.summerframework.core.exception.WebException;
import org.summerframework.core.util.OptionalUtils;
import org.summerframework.core.util.SpringContextUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Objects;

@Service("userRoleService")
public class UserRoleServiceImpl extends AbstractBasePlusService<UserRoleDAO, UserRoleDTO, UserRoleQueryDTO, UserRoleDO> implements UserRoleService {

    @Resource
    private UserRoleRelService userRoleRelService;

    @Resource
    private UserPermissionsRoleRelService userPermissionsRoleRelService;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    private BoundValueOperations<String, Object> boundValueOperations;

    @PostConstruct
    public void init() {
        boundValueOperations = redisTemplate.boundValueOps("role:counter");
    }

    @Override
    public Wrapper<UserRoleDO> getWrapper(UserRoleQueryDTO query) {
        return Wrappers.<UserRoleDO>lambdaQuery()
                .orderBy(Objects.nonNull(query.getOrderByCreateTime()), query.getOrderByCreateTime() != null ? query.getOrderByCreateTime() : false, UserRoleDO::getCreateTime)
                .orderBy(Objects.nonNull(query.getOrderByUpdateTime()), query.getOrderByUpdateTime() != null ? query.getOrderByUpdateTime() : false, UserRoleDO::getUpdateTime)
                .orderBy(Objects.nonNull(query.getOrderById()), query.getOrderById() != null ? query.getOrderById() : false, UserRoleDO::getId)
                .eq(Objects.nonNull(query.getCreateBy()), UserRoleDO::getCreateBy, query.getCreateBy())
                .like(StringUtils.isNotBlank(query.getSearchCode()), UserRoleDO::getCode, query.getSearchCode())
                .eq(StringUtils.isNotBlank(query.getCode()), UserRoleDO::getCode, query.getCode())
                .eq(Objects.nonNull(query.getUpdateBy()), UserRoleDO::getUpdateBy, query.getUpdateBy())
                .like(StringUtils.isNotBlank(query.getSearchName()), UserRoleDO::getName, query.getSearchName())
                .eq(StringUtils.isNotBlank(query.getName()), UserRoleDO::getName, query.getName())
                .eq(Objects.nonNull(query.getType()), UserRoleDO::getType, query.getType())
                .eq(Objects.nonNull(query.getStatus()), UserRoleDO::getStatus, query.getStatus())
                .eq(Objects.nonNull(query.getRelId()), UserRoleDO::getRelId, query.getRelId())
                .eq(Objects.nonNull(query.getIsSystem()), UserRoleDO::getIsSystem, query.getIsSystem())
                ;
    }

    @Override
    public UserRoleDTO insert(UserRoleDTO userRoleDTO) {
        userRoleDTO.setCode(String.format("%05d", boundValueOperations.increment(1)));
        super.insert(userRoleDTO);
        userPermissionsRoleRelService.updatePermissionsIdsByUserId(userRoleDTO.getPermissionsIds(), userRoleDTO.getId());
        return userRoleDTO;
    }

    @Override
    public Integer updateById(UserRoleDTO userRoleDTO) {
        userRoleDTO.setCode(null);
        UserRoleDTO temp = OptionalUtils.get(selectById(userRoleDTO.getId()));
        Integer count = super.updateById(userRoleDTO);
        boolean flag = false;

        if (StringUtils.isNotBlank(userRoleDTO.getName())) {
            UserPermissionsRoleRelDTO userPermissionsRoleRelDTO = new UserPermissionsRoleRelDTO();
            userPermissionsRoleRelDTO.setRoleId(userRoleDTO.getId());
            userPermissionsRoleRelDTO.setRoleName(userRoleDTO.getName());
            userPermissionsRoleRelDTO.setRoleType(userRoleDTO.getType());
            userPermissionsRoleRelDTO.setRoleRelId(userRoleDTO.getRelId());
            userPermissionsRoleRelService.updateByRoleId(userPermissionsRoleRelDTO);


            UserRoleRelDTO userRoleRelDTO = new UserRoleRelDTO();
            userRoleRelDTO.setRoleId(userRoleDTO.getId());
            userRoleRelDTO.setRoleName(userRoleDTO.getName());
            userRoleRelDTO.setStatus(userRoleDTO.getStatus());
            userRoleRelService.updateByRoleId(userRoleRelDTO);
            flag = true;
        }

        Integer updateCount = userPermissionsRoleRelService.updatePermissionsIdsByUserId(userRoleDTO.getPermissionsIds(), userRoleDTO.getId());

        if (updateCount > 0 || (userRoleDTO.getStatus() != null && !temp.getStatus().equals(userRoleDTO.getStatus()))) {
            flag = true;
        }

        if (flag) {
            SpringContextUtil.publishEvent(new RoleChangeEvent(BASE_OP.UPDATE, userRoleDTO.getId()));
        }

        return count;
    }
    @Override
    public UserRoleDTO selectByCode(String code) {
        return selectOne(UserRoleQueryDTO.builder().code(code).build());
    }

    @Override
    public boolean check(BASE_OP baseOp, UserRoleDTO baseDTO) {
        final boolean check = super.check(baseOp, baseDTO);

        if(baseDTO.getName() != null) {

            LambdaQueryWrapper<UserRoleDO> wrapper = Wrappers.<UserRoleDO>lambdaQuery().ne(baseDTO.getId() != null, UserRoleDO::getId, baseDTO.getId())
                    .eq(UserRoleDO::getName, baseDTO.getName()).eq(UserRoleDO::getType, baseDTO.getType());
            if (Objects.nonNull(baseDTO.getRelId())) {
                wrapper.eq(UserRoleDO::getRelId, baseDTO.getRelId());
            } else {
                wrapper.isNull(UserRoleDO::getRelId);
            }

            final Integer count = selectCount(wrapper);
            if (count > 0) {
                throw new WebException(DefaultResultCode.ILLEGAL_ARGUMENT, "角色名称重复, 请重新输入");
            }
        }

        if ((baseOp == BASE_OP.UPDATE || baseOp == BASE_OP.DELETE)) {
            UserRoleDTO userRoleDTO = OptionalUtils.get(this.selectById(baseDTO.getId()));
            if (1 == userRoleDTO.getIsSystem()) {
                throw new WebException(RoleResultCode.ERROR_NOT_DELETE_UPDATE_ADMIN, "该角色不可修改");
            }
        }

        if (baseDTO.getStatus() != null && baseDTO.getStatus() == 0) {
            Integer count = userRoleRelService.selectCountByQuery(UserRoleRelQueryDTO.builder().roleId(baseDTO.getId()).status(1).build());
            if (count > 0) {
                throw RoleResultCode.ERROR_HAS_USER_ROLE.format(count);
            }
        }

        return check;
    }
}
